package com.hsteach.service.meeting;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.hsteach.common.config.App;
import com.hsteach.common.config.AppConfig;
import com.hsteach.common.core.domain.model.AuthInfo;
import com.hsteach.common.core.page.TableDataInfo;
import com.hsteach.common.exception.ServiceException;
import com.hsteach.common.utils.DateUtils;
import com.hsteach.common.utils.SecurityUtils;
import com.hsteach.common.utils.StringUtils;
import com.hsteach.common.utils.sign.Base64;
import com.hsteach.common.utils.uuid.UUID;
import com.hsteach.dao.domain.buildingApply.BuildingApply;
import com.hsteach.dao.domain.buildingApply.BuildingReviewPerson;
import com.hsteach.dao.domain.meeting.MeetingApply;
import com.hsteach.dao.domain.meeting.MeetingFile;
import com.hsteach.dao.domain.meeting.MeetingPerson;
import com.hsteach.dao.domain.meeting.MeetingSummary;
import com.hsteach.dao.mapper.buildingApply.BuildingApplyMapper;
import com.hsteach.dao.mapper.meeting.MeetingApplyMapper;
import com.hsteach.dao.mapper.meeting.MeetingFileMapper;
import com.hsteach.dao.mapper.meeting.MeetingPersonMapper;
import com.hsteach.dao.mapper.meeting.MeetingSummaryMapper;
import com.hsteach.enums.*;
import com.hsteach.framework.feign.client.xgk.dto.GetPersonBySpyCodeEntity;
import com.hsteach.framework.feign.client.xgk.dto.ret.GetClassRoomListByPlaceIdRet;
import com.hsteach.framework.feign.client.xgk.dto.ret.GetPersonBySpyCodeRet;
import com.hsteach.framework.feign.client.xgk.dto.ret.GetTeacherRet;
import com.hsteach.service.buildingApply.BuildingApplyService;
import com.hsteach.service.buildingApply.RepeatApplyHandler;
import com.hsteach.service.third.MessageService;
import com.hsteach.service.third.XgkService;
import com.hsteach.web.controller.buildingApply.dto.*;
import com.hsteach.web.controller.buildingApply.vo.ListBuildingApplyVo;
import com.hsteach.web.controller.buildingApply.vo.ListHoldingTimeVo;
import com.hsteach.web.controller.buildingApply.vo.ListRoomsVo;
import com.hsteach.web.controller.buildingApply.vo.ListTimetableVo;
import com.hsteach.web.controller.meeting.dto.AddMeetingApplyDto;
import com.hsteach.web.controller.meeting.dto.AddMeetingPersonDto;
import com.hsteach.web.controller.meeting.vo.ListMeetingApplyVo;
import com.hsteach.web.controller.meeting.vo.MeetingApplyVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 会议申请-从场所申请拓展Service业务层处理
 *
 * @author fanxquer
 * @date 2023-09-19
 */
@Service
@Slf4j
public class MeetingApplyService
{
    @Autowired
    private MeetingApplyMapper meetingApplyMapper;

    @Autowired
    private BuildingApplyService buildingApplyService;

    @Autowired
    private BuildingApplyMapper buildingApplyMapper;

    @Autowired
    private MeetingFileMapper meetingFileMapper;

    @Autowired
    private MeetingSummaryMapper meetingSummaryMapper;

    @Autowired
    private MeetingPersonMapper meetingPersonMapper;

    @Autowired
    private List<RepeatApplyHandler> repeatApplyHandlers;

    @Autowired
    private MessageService messageService;

    @Autowired
    private XgkService xgkService;

    @Autowired
    private AppConfig appConfig;

    private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd");
    private static final SimpleDateFormat SDF2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private static final SimpleDateFormat SDF3 = new SimpleDateFormat("HH:mm");


    public TableDataInfo listMine(ListBuildingApplyDto dto, ApplyTypeEnum type) {
        String personId = SecurityUtils.getAuthInfo().getPersonId();
//        if (IdentityEnum.ADMIN.getCode().equals(SecurityUtils.getAuthInfo().getIdentity())) {
//            personId = null;
//        }
        TableDataInfo<ListBuildingApplyVo> tableDataInfo = buildingApplyService.listMine(dto, type, personId);
        List<Long> ids = tableDataInfo.getRows().stream().map(ListBuildingApplyVo::getId).collect(Collectors.toList());
        TableDataInfo retTable = new TableDataInfo<>();
        retTable.setTotal(tableDataInfo.getTotal());
        List<MeetingApply> meetingApplies = Lists.newArrayList();
        List<MeetingPerson> meetingPeople = Lists.newArrayList();
        if (ids.size() > 0) {
            meetingApplies = meetingApplyMapper.selectMeetingApplyByIds(ids);
            meetingPeople = meetingPersonMapper.selectByApplyIds(ids);
        }

        Map<Long, List<MeetingPerson>> personMap = meetingPeople.stream().collect(Collectors.groupingBy(MeetingPerson::getApplyId));
        Map<Long, MeetingApply> meetingMap = meetingApplies.stream().collect(Collectors.toMap(MeetingApply::getId, e -> e, (v1, v2) -> v2));
        List<ListMeetingApplyVo> ret = tableDataInfo.getRows().stream().map(e -> {
            ListMeetingApplyVo vo = new ListMeetingApplyVo();
            BeanUtils.copyProperties(e, vo);
            if (meetingMap.containsKey(vo.getId())) {
                MeetingApply meetingApply = meetingMap.get(vo.getId());
                vo.setMeetingTopic(meetingApply.getMeetingTopic());
                vo.setMeetingDesc(meetingApply.getMeetingDesc());
                vo.setNeedSign(meetingApply.getNeedSign());
            }
            // 参会人信息
            if (personMap.containsKey(vo.getId())) {
                List<MeetingPerson> persons = personMap.get(vo.getId());
                Map<String, List<MeetingPerson>> typeMap = persons.stream().collect(Collectors.groupingBy(MeetingPerson::getPersonType));
                if (typeMap.containsKey(PersonTypeEnum.COMPARE.getCode())) {
                    vo.setCompere(typeMap.get(PersonTypeEnum.COMPARE.getCode()));
                }
                if (typeMap.containsKey(PersonTypeEnum.ATTENDEE.getCode())) {
                    vo.setAttendeeNum(typeMap.get(PersonTypeEnum.ATTENDEE.getCode()).size());
                }
                if (typeMap.containsKey(PersonTypeEnum.PARTICIPANT.getCode())) {
                    vo.setParticipantNum(typeMap.get(PersonTypeEnum.PARTICIPANT.getCode()).size());
                }
            }
            return vo;
        }).collect(Collectors.toList());
        retTable.setRows(ret);
        return retTable;
    }

    public TableDataInfo listReview(ListReviewDto dto, ApplyTypeEnum type) {
        //审批状态：1已审批，0未审批
        Integer applyStatus = dto.getApplyStatus();
        TableDataInfo<ListBuildingApplyVo> tableDataInfo = listReviewMeeting(dto, type);
        List<Long> ids = tableDataInfo.getRows().stream().map(ListBuildingApplyVo::getId).collect(Collectors.toList());
        TableDataInfo retTable = new TableDataInfo<>();
        retTable.setTotal(tableDataInfo.getTotal());
        List<MeetingApply> meetingApplies = Lists.newArrayList();
        List<MeetingPerson> meetingPeople = Lists.newArrayList();
        if (ids.size() > 0) {
            meetingApplies = meetingApplyMapper.selectMeetingApplyByIds(ids);
            meetingPeople = meetingPersonMapper.selectByApplyIds(ids);
        }
        Map<Long, List<MeetingPerson>> personMap = meetingPeople.stream().collect(Collectors.groupingBy(MeetingPerson::getApplyId));
        Map<Long, MeetingApply> meetingMap = meetingApplies.stream().collect(Collectors.toMap(MeetingApply::getId, e -> e, (v1, v2) -> v2));
        List<ListBuildingApplyVo> ret = tableDataInfo.getRows();
        //数据排序
        ret = listReviewSort(applyStatus, ret);
        ret = ret.stream().map(e -> {
            ListMeetingApplyVo vo = new ListMeetingApplyVo();
            BeanUtils.copyProperties(e, vo);
            if (meetingMap.containsKey(vo.getId())) {
                MeetingApply meetingApply = meetingMap.get(vo.getId());
                vo.setMeetingTopic(meetingApply.getMeetingTopic());
                vo.setMeetingDesc(meetingApply.getMeetingDesc());
                vo.setNeedSign(meetingApply.getNeedSign());
            }
            // 参会人信息
            if (personMap.containsKey(vo.getId())) {
                List<MeetingPerson> persons = personMap.get(vo.getId());
                Map<String, List<MeetingPerson>> typeMap = persons.stream().collect(Collectors.groupingBy(MeetingPerson::getPersonType));
                if (typeMap.containsKey(PersonTypeEnum.COMPARE.getCode())) {
                    vo.setCompere(typeMap.get(PersonTypeEnum.COMPARE.getCode()));
                }
                if (typeMap.containsKey(PersonTypeEnum.ATTENDEE.getCode())) {
                    vo.setAttendeeNum(typeMap.get(PersonTypeEnum.ATTENDEE.getCode()).size());
                }
                if (typeMap.containsKey(PersonTypeEnum.PARTICIPANT.getCode())) {
                    vo.setParticipantNum(typeMap.get(PersonTypeEnum.PARTICIPANT.getCode()).size());
                }
            }
            return vo;
        }).collect(Collectors.toList());
        retTable.setRows(ret);
        return retTable;
    }

    /**
     * listReview方法的排序方法
     */
    private List<ListBuildingApplyVo> listReviewSort(Integer applyStatus,List<ListBuildingApplyVo> ret){
        //排序
        if (applyStatus == 0) {
            //待审批排序，离开会时间越近的排在最前(升序)
            ret = ret.stream().filter(e -> !ObjectUtils.isEmpty(e.getBeginTime())).sorted(Comparator.comparing(ListBuildingApplyVo::getBeginTime)).collect(Collectors.toList());
        } else if (applyStatus == 1) {
            ArrayList<ListBuildingApplyVo> tempList = new ArrayList<>();
            //已审批排序，按照审批时间排序，刚审批的排最前(降序)
            List<ListBuildingApplyVo> updateNotBlankList = ret.stream().filter(e -> !ObjectUtils.isEmpty(e.getApproveTime())).sorted(Comparator.comparing(ListBuildingApplyVo::getApproveTime).reversed()).collect(Collectors.toList());
            //修改时间为空的数据，排后面
            List<ListBuildingApplyVo> updateBlankList = ret.stream().filter(e -> ObjectUtils.isEmpty(e.getApproveTime())).collect(Collectors.toList());
            //刚审批的排最前，修改时间为空的排后面
            tempList.addAll(updateNotBlankList);
            tempList.addAll(updateBlankList);
            ret = tempList;
        }else { //全部，未审批的排最前，已审批由新到旧（刚审批的在最前(降序)）
            ArrayList<ListBuildingApplyVo> tempRet = new ArrayList<>();
            //未审批列表
            List<ListBuildingApplyVo> noApplyList = ret.stream().filter((e) -> {
                return e.getCurStatus() == 0;
            }).collect(Collectors.toList());
            //已审批列表
            List<ListBuildingApplyVo> haveApplyList = ret.stream().filter((e) -> {
                return e.getCurStatus() == 1 || e.getCurStatus() == -1;
            }).collect(Collectors.toList());
            //未审批排序，离开会时间越近的排在最前(升序)
            noApplyList = noApplyList.stream().filter(e -> !ObjectUtils.isEmpty(e.getBeginTime())).sorted(Comparator.comparing(ListBuildingApplyVo::getBeginTime)).collect(Collectors.toList());
            //已审批排序，按照审批时间排序，刚审批的排最前(降序)，修改时间不为空
            List<ListBuildingApplyVo> updateNotBlankList = haveApplyList.stream().filter(e -> !ObjectUtils.isEmpty(e.getApproveTime())).sorted(Comparator.comparing(ListBuildingApplyVo::getApproveTime).reversed()).collect(Collectors.toList());
            //已审批排序，按照审批时间排序，刚审批的排最前(降序)，修改时间不空
            List<ListBuildingApplyVo> updateBlankList = haveApplyList.stream().filter(e -> ObjectUtils.isEmpty(e.getApproveTime())).collect(Collectors.toList());
            //顺序：未审批列表(开会时间升序)-》已审批列表(时间不为空，审批时间降序)-》已审批列表(时间为空，无序)
            tempRet.addAll(noApplyList);
            tempRet.addAll(updateNotBlankList);
            tempRet.addAll(updateBlankList);
            ret = tempRet;
        }
        return ret;
    }

    public TableDataInfo<ListBuildingApplyVo> listReviewMeeting(ListReviewDto dto, ApplyTypeEnum type) {
        AuthInfo authInfo = SecurityUtils.getAuthInfo();
        // 查询可审核类型
//        BuildingReviewPerson configQuery = new BuildingReviewPerson();
//        configQuery.setApplyType(type.getCode());
//        configQuery.setOrgCode(authInfo.getOrgCode());
//        configQuery.setReviewPersonId(authInfo.getPersonId());
//        List<BuildingReviewPerson> configs = buildingReviewPersonMapper.selectBuildingReviewPersonList(configQuery);
//        List<String> buildingUses = configs.stream().map(BuildingReviewPerson::getBuildingUse).collect(Collectors.toList());
//        if (buildingUses.size() == 0) {
//            TableDataInfo tableDataInfo = new TableDataInfo(Lists.newArrayList(), 0);
//            return tableDataInfo;
//        }

        BuildingApply query = new BuildingApply();
        query.setApplyType(type.getCode());
        if (BooleanEnum.FALSE.getCode().equals(dto.getApplyStatus())) {
            query.setSGtBeginDate(DateUtils.getNowyyyyMMdd());
            query.setSGtBeginTime(new Date());
            query.setSearchStatus(Lists.newArrayList(ApplyStatusEnum.APPLY.getCode()));
        } else if (BooleanEnum.TRUE.getCode().equals(dto.getApplyStatus())) {
            query.setSearchStatus(Lists.newArrayList(ApplyStatusEnum.REJECT.getCode(), ApplyStatusEnum.PASS.getCode()));
            query.setSReview(authInfo.getPersonId());
        } else {
            query.setSGtBeginDate(DateUtils.getNowyyyyMMdd());
            query.setSGtBeginTime(new Date());
            query.setSearchStatus(Lists.newArrayList(ApplyStatusEnum.APPLY.getCode(), ApplyStatusEnum.REJECT.getCode(), ApplyStatusEnum.PASS.getCode()));
            query.setSReview(authInfo.getPersonId());
        }
        query.setOrgCode(authInfo.getOrgCode());
//        query.setBuildingUses(buildingUses);
        query.setTimeModes(Lists.newArrayList(0,1));
        PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
        List<BuildingApply> buildingApplies = buildingApplyMapper.selectBuildingApplyReviewList(query);
        Long total = new PageInfo(buildingApplies).getTotal();
        List<ListBuildingApplyVo> ret = buildingApplies.stream().map(e -> {
            ListBuildingApplyVo vo = new ListBuildingApplyVo();
            BeanUtils.copyProperties(e, vo);
            if (ApplyStatusEnum.APPLY.getCode().equals(e.getCurStatus())) {
                vo.setApplyStatus(BooleanEnum.FALSE.getCode());
            } else {
                vo.setApplyStatus(BooleanEnum.TRUE.getCode());
            }
            if (BooleanEnum.TRUE.getCode().equals(e.getRepeatStatus()) && e.getRepeatBeginDate() != null) {
                Calendar date = Calendar.getInstance();
                date.setTime(e.getRepeatBeginDate());
                Calendar beginTime = Calendar.getInstance();
                beginTime.setTime(vo.getBeginTime());
                beginTime.set(date.get(Calendar.YEAR), date.get(Calendar.MONTH), date.get(Calendar.DAY_OF_MONTH));
                vo.setRepeatBeginDate(beginTime.getTime());
            }
            return vo;
        }).collect(Collectors.toList());
        TableDataInfo tableDataInfo = new TableDataInfo(ret, total);
        return tableDataInfo;
    }

    public MeetingApplyVo getInfo(Long id) {
        BuildingApply apply = buildingApplyMapper.selectBuildingApplyById(id);
        MeetingApply meetingApply = meetingApplyMapper.selectMeetingApplyById(id);
        List<MeetingFile> meetingFiles = meetingFileMapper.selectByApplyId(id);
        List<MeetingSummary> meetingSummaries = meetingSummaryMapper.selectList(id);
        MeetingPerson query = new MeetingPerson();
        query.setApplyId(id);
        query.setDelStatus(BooleanEnum.TRUE.getCode());
        List<MeetingPerson> meetingPeople = meetingPersonMapper.selectList(query);

        MeetingApplyVo vo = new MeetingApplyVo();
        BeanUtils.copyProperties(apply, vo);
        BeanUtils.copyProperties(meetingApply, vo);
        vo.setFiles(meetingFiles);
        vo.setSummaries(meetingSummaries);
        Map<String, List<MeetingPerson>> typeMap = meetingPeople.stream().collect(Collectors.groupingBy(MeetingPerson::getPersonType));
        if (typeMap.containsKey(PersonTypeEnum.COMPARE.getCode())) {
            vo.setCompere(typeMap.get(PersonTypeEnum.COMPARE.getCode()));
        }
        if (typeMap.containsKey(PersonTypeEnum.ATTENDEE.getCode())) {
            vo.setAttendee(typeMap.get(PersonTypeEnum.ATTENDEE.getCode()));
        }
        if (typeMap.containsKey(PersonTypeEnum.PARTICIPANT.getCode())) {
            vo.setParticipant(typeMap.get(PersonTypeEnum.PARTICIPANT.getCode()));
        }

        MeetingPerson person = meetingPeople.stream().filter(e -> SecurityUtils.getAuthInfo().getPersonId().equals(e.getPersonId()))
                .findFirst().orElse(null);
        if (person != null) {
            vo.setSignInStatus(person.getSignInStatus());
        } else {
            vo.setSignInStatus(-1);
        }
        if (ApplyStatusEnum.PASS.getCode().equals(apply.getCurStatus()) || ApplyStatusEnum.REJECT.getCode().equals(apply.getCurStatus())) {
            vo.setApplyStatus(BooleanEnum.TRUE.getCode());
        } else {
            vo.setApplyStatus(BooleanEnum.FALSE.getCode());
        }

        if (BooleanEnum.TRUE.getCode().equals(apply.getRepeatStatus()) && apply.getRepeatBeginDate() != null) {
            Calendar date = Calendar.getInstance();
            date.setTime(apply.getRepeatBeginDate());
            Calendar beginTime = Calendar.getInstance();
            beginTime.setTime(vo.getBeginTime());
            beginTime.set(date.get(Calendar.YEAR), date.get(Calendar.MONTH), date.get(Calendar.DAY_OF_MONTH));
            vo.setRepeatBeginDate(beginTime.getTime());
        } else {
            vo.setRepeatBeginDate(vo.getBeginTime());
        }
        return vo;
    }

    public List<ListHoldingTimeVo> listHoldingTime(ListHoldingTimeDto dto) {
        return listHoldingTime(dto.getBeginDate(), Lists.newArrayList(dto.getBuildingId()));
    }

    public List<ListTimetableVo> listTimetable(ListTimetableDto dto) {
        return Lists.newArrayList(
                new ListTimetableVo("07:00", "07:50", "早自习"),
                new ListTimetableVo("08:00", "08:50", "第一节"),
                new ListTimetableVo("09:00", "09:50", "第二节"),
                new ListTimetableVo("10:00", "10:50", "第三节"),
                new ListTimetableVo("11:00", "11:50", "第四节"),
                new ListTimetableVo("11:50", "13:00", "午休"),
                new ListTimetableVo("13:00", "13:50", "第五节"),
                new ListTimetableVo("14:00", "14:50", "眼保健操"),
                new ListTimetableVo("15:00", "15:50", "第六节"),
                new ListTimetableVo("16:00", "16:50", "第七节"),
                new ListTimetableVo("17:00", "17:50", "第八节"),
                new ListTimetableVo("17:50", "18:00", "晚餐"),
                new ListTimetableVo("18:00", "18:50", "晚自习"),
                new ListTimetableVo("19:00", "19:50", "第九节"),
                new ListTimetableVo("20:00", "20:50", "第十节")

        );
//        List<QuerySinglePlaceTableRet> querySinglePlaceTableRets = xgkService.querySinglePlaceTable(dto.getBuildingId(), DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, dto.getDate()));
//        List<ListTimetableVo> ret = querySinglePlaceTableRets.stream()
//                .sorted(Comparator.comparing(QuerySinglePlaceTableRet::getTeachLesSortOptIndex, Comparator.comparingInt(Integer::valueOf)))
//                .map(e -> {
//                    ListTimetableVo vo = new ListTimetableVo();
//                    if (StringUtils.isNotEmpty(e.getLesTime())) {
//                        String[] split = e.getLesTime().split("-");
//                        vo.setBeginTime(Optional.ofNullable(split[0]).orElse(""));
//                        vo.setEndTime(Optional.ofNullable(split[1]).orElse(""));
//                    }
//                    vo.setTeachLesSortOptName(e.getTeachLesSortOptName());
//                    return vo;
//                }).collect(Collectors.toList());
//        return ret;
    }

    public List<ListRoomsVo> listRooms(String buildingId, Integer type, Date date) {
        List<GetClassRoomListByPlaceIdRet> rooms = xgkService.getClassRoomListByPlaceId(type, buildingId);
        rooms = rooms.stream().filter(e -> BuildingUseEnum.match(ApplyTypeEnum.MEETING, e.getUseId())).collect(Collectors.toList());
        List<String> buildingIds = rooms.stream().map(GetClassRoomListByPlaceIdRet::getClassroomId).collect(Collectors.toList());
        List<ListHoldingTimeVo> listHoldingTimeVos = listHoldingTime(date, buildingIds);
        Map<String, List<ListHoldingTimeVo>> timeMap = listHoldingTimeVos.stream().collect(Collectors.groupingBy(ListHoldingTimeVo::getBuildingId));
        List<ListRoomsVo> ret = rooms.stream().map(e -> {
            ListRoomsVo vo = new ListRoomsVo();
            BeanUtils.copyProperties(e, vo);
            vo.setHoldTime(timeMap.getOrDefault(e.getClassroomId(), Lists.newArrayList()));
            return vo;
        }).collect(Collectors.toList());
        return ret;
    }

    private List<ListHoldingTimeVo> listHoldingTime(Date beginDate, List<String> buildingIds) {
        BuildingApply query = new BuildingApply();
        query.setOrgCode(SecurityUtils.getAuthInfo().getOrgCode());
        query.setBeginDate(beginDate);
        query.setSearchStatus(Lists.newArrayList(ApplyStatusEnum.APPLY.getCode(), ApplyStatusEnum.PASS.getCode()));
        query.setBuildingIds(buildingIds);
        query.setTimeModes(Lists.newArrayList(0,1));
        List<BuildingApply> buildingApplies = buildingApplyMapper.selectBuildingApplyList(query);
        List<ListHoldingTimeVo> ret = buildingApplies.stream().map(e -> {
            ListHoldingTimeVo vo = new ListHoldingTimeVo();
            vo.setBeginTime(e.getBeginTime());
            vo.setEndTime(e.getEndTime());
            vo.setBuildingId(e.getBuildingId());
            return vo;
        }).collect(Collectors.toList());
        return ret;
    }


    @Transactional(rollbackFor = Exception.class)
    public int buildingApply(AddMeetingApplyDto dto, ApplyTypeEnum type)
    {
        // 没有场所时使用不占用时间线的方式
        if (StringUtils.isEmpty(dto.getBuildingId())) {
            dto.setTimeMode(-1);
        }
        BuildingApply apply = new BuildingApply();
        BeanUtils.copyProperties(dto, apply);
        AuthInfo authInfo = SecurityUtils.getAuthInfo();
        apply.setCreateByName(authInfo.getName());
        apply.setCreateBy(authInfo.getPersonId());
        apply.setCreateTime(DateUtils.getNowDate());
        apply.setPersonId(authInfo.getPersonId());
        apply.setCurStatus(ApplyStatusEnum.APPLY.getCode());
        apply.setDelStatus(BooleanEnum.TRUE.getCode());
        apply.setOrgCode(authInfo.getOrgCode());
        apply.setApplyName(apply.getBuildingName());
        apply.setBeginDate(apply.getBeginTime());
        apply.setRepeatBeginDate(apply.getBeginTime());
        UUID uuid = UUID.fastUUID();
        String repeatId = uuid.toString(true);
        apply.setRepeatId(repeatId);

        List<BuildingApply> applies = Lists.newArrayList(apply);
        // 重复申请处理
        if (BooleanEnum.TRUE.getCode().equals(dto.getRepeatStatus())) {
            RepeatApplyHandler repeatApplyHandler = repeatApplyHandlers.stream().filter(e -> e.getType().getCode().equals(dto.getRepeatType())).findFirst().orElse(null);
            if (repeatApplyHandler == null) {
                throw new ServiceException("重复申请处理错误");
            }
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(dto.getRepeatEndDate());
            calendar.add(Calendar.DATE, 1);
            List<BuildingApply> repeatList = repeatApplyHandler.handle(apply, dto.getBeginTime(), calendar.getTime());
            String id = uuid.toString(true);
            repeatList.stream().forEach(e -> {
                e.setRepeatId(id);
            });
            if (repeatList.size() > 0) {
                applies = repeatList;
            } else {
                throw new ServiceException("重复申请处理错误");
            }
        }
        if (StringUtils.isNotEmpty(dto.getBuildingId())) {
            // 校验时间段是否有其他预约
            validApply(applies);
        }

        applies.stream().forEach(e -> {
            // 插入场馆申请信息
            int i = buildingApplyMapper.insertBuildingApply(e);
            if (i <= 0) {
                throw new ServiceException("申请错误");
            }
            MeetingApply meetingApply = new MeetingApply();
            BeanUtils.copyProperties(dto, meetingApply);
            meetingApply.setId(e.getId());
            // 插入会议信息
            meetingApplyMapper.insertMeetingApply(meetingApply);
            // 插入参会人
            List<MeetingPerson> meetingPeople = genPerson(dto.getAttendee(), e.getId(), PersonTypeEnum.ATTENDEE);
            meetingPeople.addAll(genPerson(dto.getCompere(), e.getId(), PersonTypeEnum.COMPARE));
            meetingPeople.addAll(genPerson(dto.getParticipant(), e.getId(), PersonTypeEnum.PARTICIPANT));
            if (meetingPeople.size() > 0) {
                meetingPersonMapper.batchInsert(meetingPeople);
            }
            // 插入附件
            if(dto.getFiles() != null && dto.getFiles().size() > 0) {
                List<MeetingFile> files = dto.getFiles().stream().map(k -> {
                    MeetingFile file = new MeetingFile();
                    BeanUtils.copyProperties(k, file);
                    file.setDelStatus(BooleanEnum.TRUE.getCode());
                    file.setCorrelationId(e.getId());
                    return file;
                }).collect(Collectors.toList());
                meetingFileMapper.batchInsert(files);
            }


        });
        // todo:待验证
        try {
            // 发送审核通知
            sendMsg(applies.get(0));
        } catch (Exception e) {
            log.error("发送信息失败", e);
        }
        return applies.size();
    }

    private void sendMsg(BuildingApply apply) throws UnsupportedEncodingException {
        App app = appConfig.getConfig().get(SecurityUtils.getAuthInfo().getAppId());
        if (app != null) {
            GetPersonBySpyCodeEntity entity = new GetPersonBySpyCodeEntity();
            entity.setAppId(app.getAuthAppId());
            entity.setSpyCode(app.getMsgSpyCode());
            List<GetPersonBySpyCodeRet> personBySpyCode = xgkService.getPersonBySpyCode(entity);
            if (CollectionUtils.isNotEmpty(personBySpyCode)) {
                String title = SecurityUtils.getAuthInfo().getName()
                        + "申请预约" + Optional.ofNullable(apply.getParentBuildingName()).orElse("") + " " + apply.getBuildingName();
                String msg;
                if (BooleanEnum.TRUE.getCode().equals(apply.getRepeatStatus())) {
                    msg = title + "，日期" + DateUtils.parseDateToStr("MM-dd", apply.getRepeatBeginDate()) + "至" + DateUtils.parseDateToStr("MM-dd", apply.getRepeatEndDate())
                            + "，时间" + DateUtils.parseDateToStr("HH:mm", apply.getBeginTime()) + "-" + DateUtils.parseDateToStr("HH:mm", apply.getEndTime());
                } else {
                    msg = title + "，日期" + DateUtils.parseDateToStr("MM-dd", apply.getBeginTime())
                            + "，时间" + DateUtils.parseDateToStr("HH:mm", apply.getBeginTime()) + "-" + DateUtils.parseDateToStr("HH:mm", apply.getEndTime());
                }
                String eStr = "/meeting-details?id=" + apply.getId() + "&type=approve";
                String encode = Base64.encode(eStr.getBytes(StandardCharsets.UTF_8));
//                String encode = URLEncoder.encode(eStr, "UTF-8");
                String params = "&e=" + encode ;
                String url = app.getRedirectUrl() + params;
                String content = "<p>" + msg + "<a href=\"" + url + "\">跳转进应用</a></p>";
                List<String> tPersonId = personBySpyCode.stream().map(GetPersonBySpyCodeRet::getThirdId).collect(Collectors.toList());
                messageService.sendMsgByTPersonId(content, tPersonId, MsgTypeEnum.MEETING_REVIEW_NOTIFY, title);
            }
        }
    }

    private void sendReviewMsg(BuildingApply apply, Integer status) throws UnsupportedEncodingException {
        App app = appConfig.getConfig().get(SecurityUtils.getAuthInfo().getAppId());
        if (app == null) {
            return;
        }
        String title =  Optional.ofNullable(apply.getParentBuildingName()).orElse("") + " " + apply.getBuildingName();
        if (ApplyStatusEnum.PASS.getCode().equals(status)) {
            title = title + "申请审批已通过";
        }

        if (ApplyStatusEnum.REJECT.getCode().equals(status)) {
            title = title + "申请审批已拒绝";
        }

        String msg;
        if (BooleanEnum.TRUE.getCode().equals(apply.getRepeatStatus())) {
            msg = "申请时间为" + DateUtils.parseDateToStr("MM-dd", apply.getRepeatBeginDate()) + "至" + DateUtils.parseDateToStr("MM-dd", apply.getRepeatEndDate())
                    + " " + DateUtils.parseDateToStr("HH:mm", apply.getBeginTime()) + "-" + DateUtils.parseDateToStr("HH:mm", apply.getEndTime());
        } else {
            msg = "申请时间为" + DateUtils.parseDateToStr("MM-dd", apply.getBeginTime())
            + " " + DateUtils.parseDateToStr("HH:mm", apply.getBeginTime()) + "-" + DateUtils.parseDateToStr("HH:mm", apply.getEndTime());
        }

        String eStr = "/meeting-details?id=" + apply.getId() + "&type=apply";
        String encode = Base64.encode(eStr.getBytes(StandardCharsets.UTF_8));
//        String encode = URLEncoder.encode(eStr, "UTF-8");
        String params = "&e=" + encode ;
        String url = app.getRedirectUrl() + params;
        String content = "<p>" + msg + "<a href=\"" + url + "\">跳转进应用</a></p>";
        List<GetTeacherRet> teachers = xgkService.getTeachers(SecurityUtils.getAuthInfo().getId());
        Map<String, String> teacherMap = teachers.stream().filter(e -> e.getT_userID() != null).collect(Collectors.toMap(GetTeacherRet::getPersonId, GetTeacherRet::getT_userID, (v1, v2) -> v2));

        if (teacherMap.containsKey(apply.getPersonId())) {
            messageService.sendMsg(content, Lists.newArrayList(teacherMap.get(apply.getPersonId())), MsgTypeEnum.BUILDING_REVIEW_NOTIFY, title);
        }
    }

    private List<MeetingPerson> genPerson(List<AddMeetingPersonDto> list, Long id, PersonTypeEnum typeEnum) {
        String personId = SecurityUtils.getAuthInfo().getPersonId();
        return list.stream().map(k -> {
            MeetingPerson person = new MeetingPerson();
            person.setApplyId(id);
            person.setPersonId(k.getPersonId());
            person.setPersonName(k.getPersonName());
            person.setPersonType(typeEnum.getCode());
            person.setDelStatus(BooleanEnum.TRUE.getCode());
            person.setSignInStatus(BooleanEnum.FALSE.getCode());
            person.setCreateBy(personId);
            return person;
        }).collect(Collectors.toList());
    }

    private boolean validApply(List<BuildingApply> applies) {
        List<String> buildIds = applies.stream().map(BuildingApply::getBuildingId).collect(Collectors.toList());
        List<Date> dates = applies.stream().map(e -> {
            String format = SDF.format(e.getBeginDate());
            try {
                return SDF.parse(format);
            } catch (ParseException ex) {
                throw new ServiceException(ex.getMessage());
            }
        }).collect(Collectors.toList());
        List<BuildingApply> buildingApplies = buildingApplyMapper.selectByDateAndBuildId(SecurityUtils.getAuthInfo().getOrgCode(), dates, buildIds);
        buildingApplies.stream().forEach(e -> {
            for (int i = 0;i < applies.size();i++) {
                BuildingApply apply = applies.get(i);
                // 申请开始时间在其他申请时间范围内或者结束时间在其他申请时间范围内，则校验不通过
                if ((apply.getBeginTime().compareTo(e.getBeginTime()) > 0 && apply.getBeginTime().compareTo(e.getEndTime()) < 0)
                        || (apply.getEndTime().compareTo(e.getBeginTime()) > 0 && apply.getEndTime().compareTo(e.getEndTime()) < 0)) {
                    String error = apply.getBuildingName() + "场馆"  + SDF3.format(apply.getBeginDate()) + "-" +
                            SDF3.format(apply.getEndTime()) + "时间段已被预约，请重新预约";
                    throw new ServiceException(error);
                }
                // 校验完全相同的时间
                if (apply.getBeginTime().compareTo(e.getBeginTime()) == 0 && apply.getEndTime().compareTo(e.getEndTime()) == 0) {
                    String error = apply.getBuildingName() + "场馆" + SDF3.format(apply.getBeginDate()) + "-" +
                            SDF3.format(apply.getEndTime()) + "时间段已被预约，请重新预约";
                    throw new ServiceException(error);
                }
            }
        });
        return true;
    }

    public int review(ReviewDto dto) {
        AuthInfo authInfo = SecurityUtils.getAuthInfo();
        BuildingApply update = new BuildingApply();
        update.setId(dto.getId());
        update.setReviewBy(authInfo.getPersonId());
        update.setReviewByName(authInfo.getName());
        update.setCurStatus(dto.getReviewStatus());
        update.setRejectReason(dto.getRejectReason());
        //审批时间
        update.setApproveTime(new Date());
        BuildingApply buildingApply = buildingApplyMapper.selectBuildingApplyById(dto.getId());
        if (BooleanEnum.TRUE.getCode().equals(buildingApply.getRepeatStatus())) {
            update.setRepeatId(buildingApply.getRepeatId());
            buildingApplyMapper.updateByRepeatId(update);
        } else {
            buildingApplyMapper.updateBuildingApply(update);
        }
        try {
            sendReviewMsg(buildingApply, dto.getReviewStatus());
        } catch (Exception e) {
            log.error("发送信息失败", e);
        }
        return 1;
    }

    public int cancelApply(CancelApplyDto dto)
    {
        BuildingApply apply = buildingApplyMapper.selectBuildingApplyById(dto.getId());
        int i;
        if (new Integer(1).equals(dto.getCancelType())) {
            if (StringUtils.isNotEmpty(apply.getRepeatId())) {
                BuildingApply query = new BuildingApply();
                query.setRepeatId(apply.getRepeatId());
                query.setOrgCode(SecurityUtils.getAuthInfo().getOrgCode());
                query.setGtBeginDate(DateUtils.getNowyyyyMMdd());
                query.setGtBeginTime(new Date());
                query.setSearchStatus(Lists.newArrayList(ApplyStatusEnum.APPLY.getCode(), ApplyStatusEnum.PASS.getCode()));
                List<BuildingApply> buildingApplies = buildingApplyMapper.selectBuildingApplyList(query);
                List<Long> ids = buildingApplies.stream().map(BuildingApply::getId).collect(Collectors.toList());
                i = buildingApplyMapper.batchCancel(ids);
            }
            return 1;
        } else {
            if (ApplyStatusEnum.CANCEL.getCode().equals(apply.getStatus())) {
                throw new ServiceException("不能重复取消");
            }
            if (apply.getBeginTime().getTime() < System.currentTimeMillis()) {
                throw new ServiceException("该申请已开始，无法取消");
            }
            apply.setCurStatus(ApplyStatusEnum.CANCEL.getCode());
            i = buildingApplyMapper.updateBuildingApply(apply);
        }
        return i;
    }

    /**
     * 查询会议申请-从场所申请拓展
     *
     * @param id 会议申请-从场所申请拓展主键
     * @return 会议申请-从场所申请拓展
     */
    public MeetingApply selectMeetingApplyById(Long id)
    {
        return meetingApplyMapper.selectMeetingApplyById(id);
    }

    /**
     * 查询会议申请-从场所申请拓展列表
     *
     * @param meetingApply 会议申请-从场所申请拓展
     * @return 会议申请-从场所申请拓展
     */
    public List<MeetingApply> selectMeetingApplyList(MeetingApply meetingApply)
    {
        return meetingApplyMapper.selectMeetingApplyList(meetingApply);
    }

    /**
     * 新增会议申请-从场所申请拓展
     *
     * @param meetingApply 会议申请-从场所申请拓展
     * @return 结果
     */
    public int insertMeetingApply(MeetingApply meetingApply)
    {
        return meetingApplyMapper.insertMeetingApply(meetingApply);
    }

    /**
     * 修改会议申请-从场所申请拓展
     *
     * @param meetingApply 会议申请-从场所申请拓展
     * @return 结果
     */
    public int updateMeetingApply(MeetingApply meetingApply)
    {
        return meetingApplyMapper.updateMeetingApply(meetingApply);
    }

    /**
     * 批量删除会议申请-从场所申请拓展
     *
     * @param ids 需要删除的会议申请-从场所申请拓展主键
     * @return 结果
     */
    public int deleteMeetingApplyByIds(Long[] ids)
    {
        return meetingApplyMapper.deleteMeetingApplyByIds(ids);
    }

    /**
     * 删除会议申请-从场所申请拓展信息
     *
     * @param id 会议申请-从场所申请拓展主键
     * @return 结果
     */
    public int deleteMeetingApplyById(Long id)
    {
        return meetingApplyMapper.deleteMeetingApplyById(id);
    }
}
